'''
Created on 21/10/2012

@author: Chris
'''

import os, tkMessageBox, subprocess
from tkFileDialog import askopenfilename, askdirectory, asksaveasfilename
from dialog import AddRepoDialog, AddCommentDialog, RenameDialog, SearchDialog, AutoSaveDialog, CompareDialog, AboutDialog
from gitcmd import *
from util import get_file_size, report_exception


#=======================================================================================
def open_repository(controller):
#=======================================================================================
    '''
    description: open working directory for selected git repository
    '''      
    repo,  file_property = controller.get_current_repo_file()
    if repo == None:
        report_exception("Please select a repository!")
        return
    
    os.startfile(repo.working_dir)


#=======================================================================================
def add_repository(controller):
#=======================================================================================
#    add_repo_dlg = AddRepoDialog(controller)
    add_repo_dlg = AddRepoDialog(controller)
    controller.root.wait_window(add_repo_dlg)
    repo_name, repo_dir = add_repo_dlg.get_repo_info()
    
    if (repo_name == "") or (repo_dir == "") :
        return
    
    # repo_dir is a git repository, just add it to config
    if is_valid_repo_dir(repo_dir):
        controller.add_repo_node(repo_name, repo_dir)
    # ask user if need create a new git repository
    elif (repo_dir is not None) or (repo_dir != "") :
        msg = "\"%s\" is not a git repository, do you want to create it?"%repo_dir
        is_create_repo = tkMessageBox.askyesno("Create New Repository", msg)
        if is_create_repo:
            is_success, repo = create_git_repository(repo_dir)
            if is_success:
                controller.add_repo_node(repo_name, repo_dir, repo)
        else:
            return

#=======================================================================================
def remove_repo_node(controller):
#=======================================================================================
    msg = "Remove the selected repository?"
    is_del_repo = tkMessageBox.askyesno("Remove Repository", msg)
    if is_del_repo:
        controller.remove_repo_node()
    else:
        return

#=======================================================================================
def import_repository():
#=======================================================================================
    pass

#=======================================================================================
def export_repository():
#=======================================================================================
    pass


#=======================================================================================
def check_file_for_operation(file_property, operation):
#=======================================================================================
    '''
    description: check if file can be operated by git

    parameter: file_property, four-element tuple, (file_name, file_type, file_status, file_path)
    return   : boolean, return true if file type is not directory, the size is non-zero and 
                        the status is untracked
    '''
    (file_name, file_type, file_status, file_path) = file_property
    
    # check for addition
    if operation == 'add':
        # operation only can be performed on non-empty files 
        if file_type == "directory":
            report_exception("Please select file!")
            return False
        elif file_status == "tracked":
            report_exception("Tracked file can't be added!")
            return False
        elif file_type == "file" and (get_file_size(file_path) == 0 ):
            report_exception("Empty file can't be operated!")
            return False
    
    # check for remove
    elif operation == 'remove':
        if file_type == "directory":
            report_exception("Please select file!")
            return False
        elif file_status == "untracked":
            report_exception("Untracked file can't be removed!")
            return False
    return True

#=======================================================================================
def track_file(controller):
#=======================================================================================
    '''
    description: add file to git and commit and the file can be empty (adding empty file is denied by git)
    parameter  : controller, the DM main class instance, get interface to other components from it
    '''
    repo,  file_property = controller.get_current_repo_file()
    
    if (repo is None) or (file_property is None):
        report_exception("Please select file first!")
        return
    
    if not check_file_for_operation(file_property, 'add'):
        return
    
    file_path = file_property[3]
    
    # inform main update browser
    comment_dlg = AddCommentDialog(controller.root)
    controller.root.wait_window(comment_dlg)
      
    comment = comment_dlg.get_comment()  
    
    if comment == None:
        return
    
    if len(comment) <= 1:
        return
        
    add_file_to_git(repo, file_path, comment)
    
    # inform main update browser
    controller.udpate_browser()


#=======================================================================================
def track_all_files(controller):
#=======================================================================================
    '''
    description: commit all files to git
    parameter  : controller, the DM main class instance, get interface to other components from it
    '''
    repo,  file_property = controller.get_current_repo_file()
    
    if (repo is None) or (file_property is None):
        report_exception("Please select file first!")
        return
    
    untrackd_files = query_file_status(repo) 
    
    if len(untrackd_files) == 0:
        return
    
    # find all files need to be tracked
    file_list = []
    for file_path in untrackd_files.iterkeys():
        file_status = untrackd_files[file_path]
        if get_file_size(file_path) != 0 and file_status != '??':
            file_list.append(file_path)
    
    # commit all files
    if len(file_list) > 0:  
        for file_path in file_list:
            file_name = os.path.basename(file_path) 
            comment = "DM auto commit, " + file_name
            add_file_to_git(repo, file_path, comment)
    
    # inform main update browser
    controller.udpate_browser()

#=======================================================================================
def untrack_file(controller):
#=======================================================================================
    '''
    description: remove file from control of git, the file is deleted under the working directory
    parameter  : controller, the DM main class instance, get interface to other components from it
    '''
    
    repo,  file_property = controller.get_current_repo_file()
    
    if (repo is None) or (file_property is None):
        report_exception("Please select file first!")
        return
    
    if (repo is None) or (file_property is None):
        report_exception("Please select file first!")
    
    if not check_file_for_operation(file_property, 'remove'):
        return
    
    file_path = file_property[3]
    
    # receive comment from user input
    comment_dlg = AddCommentDialog(controller.root)
    controller.root.wait_window(comment_dlg)
      
    comment = comment_dlg.get_comment()  
    
    if comment == None:
        return
    
    if len(comment) <= 1:
        return
    
    remove_file_from_git(repo, file_path, comment)
    
    # inform main update browser
    controller.udpate_browser()
    
#=======================================================================================
def rename_file(controller):
#=======================================================================================    
    '''
    description: rename files in git
    parameter  : controller, the DM main class instance, get interface to other components from it
    ''' 

    repo,  file_property = controller.get_current_repo_file()
    
    if (repo is None) or (file_property is None):
        report_exception("Please select file first!")
        return
    
    if (repo is None) or (file_property is None):
        report_exception("Please select file first!")
    
    if not check_file_for_operation(file_property, 'remove'):
        return
    
    file_name = file_property[0]
    file_type = '.' + file_name.split('.')[1]
    file_path = file_property[3]
    work_dir = file_path
    file_path = file_path + "\\" + file_name
    
    # receive new file name from user input
    rename_dlg = RenameDialog(file_path, controller.root)
    controller.root.wait_window(rename_dlg)
      
    new_file_name = rename_dlg.get_new_file_name()
    
    if new_file_name == None:
        return
    
    if len(new_file_name) <= 0:
        return
    
    
    
    new_file_path = work_dir + "\\" +new_file_name + file_type
    
    
    # receive comment from user input
    comment_dlg = AddCommentDialog(controller.root)
    controller.root.wait_window(comment_dlg)
      
    comment = comment_dlg.get_comment()  
    
    if comment == None:
        return
    
    if len(comment) <= 1:
        return
    
    rename_file_in_git(repo, file_path, new_file_path, comment)
    
    # inform main update browser
    controller.udpate_browser()
    
#=======================================================================================
def view_file_version(controller):
#=======================================================================================
    '''
    description: copy the specified history version of files in git and save it in the specified folder
    parameter  : controller, the DM main class instance, get interface to other components from it
    ''' 
    
    length = len(controller.get_selected_commit_blob())
    if length == 0 :
        report_exception("Please select file version from file history browser!")
        return
    # the original file name
    file_name = controller.get_current_repo_file()[1][0]

    # file extension
    file_type = '.' + file_name.split('.')[1]
    
    # get the blob from git
    blob = controller.get_selected_commit_blob()[1]
    
    options = {}
    options['defaultextension'] = file_type
    options['filetypes'] = [('files', file_type)]
    options['initialdir'] = controller.get_tmp_dir()
    options['initialfile'] = file_name
    options['parent'] = controller.root
    options['title'] = 'Save file version'
    
    new_file_path = asksaveasfilename(**options) #mode='w+b', 
    
    
    # user cancel the view 
    if new_file_path == None:
        return
    
    if len(new_file_path) <= 0:
        return
    
    # check out the file to the specified path
    chekout_file_version_from_git(blob, new_file_path)
    
    
#=======================================================================================
def search_file(controller):
#=======================================================================================
    '''
    description: find file version which have keywords in their comments
    ''' 
    repo, file_property = controller.get_current_repo_file()
    if repo == None or file_property == None:
        report_exception("Please select file from file tree browser!")
        return

    file_name = file_property[0]
    search_dlg = SearchDialog(controller.root)
    controller.root.wait_window(search_dlg)
    
    keywords = search_dlg.get_keywords()
    
    if keywords == None:
        return
    
    if len(keywords) <= 0:
        return
    
    controller.search_file(file_name, keywords, repo)
    
#=======================================================================================
def checkout_file_version(controller):
#=======================================================================================
    '''
    description: check out the specified history version of files in git
    parameter  : controller, the DM main class instance, get interface to other components from it
    ''' 
    repo, file_property = controller.get_current_repo_file()
    
    if repo == None or file_property == None:
        report_exception("Please select file version from file history browser!")
        return
    
    # get the file which is need to be checked out
    file_path = file_property[3]
    
    length = len(controller.get_selected_commit_blob())
    if length == 0 :
        report_exception("Please select file version from file history browser!")
        return
    
    if repo.is_dirty():
        msg = "Files in selected repository are not saved, do you want to track them? \
                If this operation is cancelled, the files may be override, or commit it by yourself"
        is_need_track = tkMessageBox.askyesno("Track all files", msg)
        if is_need_track:
            track_all_files(controller)
        else:
            return
    
    
    blob = controller.get_selected_commit_blob()[1]
    # check out the file to the specified path
    chekout_file_version_from_git(blob, file_path)
    
    # commit checkouted file version
    index = repo.index
    commnet = "checkout history version for: " + file_path
    index.commit(commnet)
    
    # inform main update browser
    controller.udpate_browser()
    
#=======================================================================================
def compare_version(controller):
#=======================================================================================
    '''
    description: compare two history versions for selected file
    parameter  : controller, the DM main class instance, get interface to other components from it
    ''' 
    repo, file_property = controller.get_current_repo_file()
    
    if repo == None or file_property == None:
        report_exception("Please select file version from file history browser!")
        return
    
    # get the file which is need to be checked out
    file_name = file_property[0]        
        
    blob_list = get_file_cmit_history(file_name, repo)
    if len(blob_list) == 0:
        report_exception("No history version of this file exists!")
        return
    
    compare_dlg = CompareDialog(file_name, blob_list, controller.root)
    controller.root.wait_window(compare_dlg)
    
    # get selected blobs and version index for comparison
    left_blob, left_version, right_blob, right_version = compare_dlg.get_blobs_for_comparison()
    
    # user canceld the selection
    if left_blob == None:
        return
    
    tmp_dir = controller.get_tmp_dir()
    
    # construct file paths
    left_file_path  = ''
    right_file_path = ''
    file_base_name = file_name.split('.')[0]
    file_extension = '.'+file_name.split('.')[1]
    # if two version index are the same, use L and R to distinguish them 
    if left_version == right_version:
        file_new_name = file_base_name + '(L-' + left_version + ')' + file_extension
        left_file_path  = tmp_dir + file_new_name
        
        file_new_name = file_base_name + '(R-' + right_version + ')' + file_extension
        right_file_path = tmp_dir + file_new_name
        
    else:
        file_new_name = file_base_name + '(' + left_version + ')' + file_extension
        left_file_path  = tmp_dir + file_new_name
        
        file_new_name = file_base_name + '(' + right_version + ')' + file_extension
        right_file_path = tmp_dir + file_new_name
    
    # write two versions to temp directory and open them with compare tools    
    chekout_file_version_from_git(left_blob, left_file_path)
    chekout_file_version_from_git(right_blob, right_file_path)
    
    # get command tool from controller
    cmd_tool = controller.get_compare_tool()
    try:
        subprocess.call([cmd_tool, left_file_path, right_file_path])
    except WindowsError:
        report_exception("Comparison tool is invalid, please config it!")
    os.startfile(tmp_dir)
    
#=======================================================================================
def cnfg_atuosave(controller):
#=======================================================================================
    '''
    description: config auto save function
    parameter  : controller, the DM main class instance, get interface to other components from it
    ''' 
    auto_save_repos, auto_save_interval = controller.get_auto_save_config()
    auto_save_dlg = AutoSaveDialog(auto_save_repos, auto_save_interval, controller.root)
    controller.root.wait_window(auto_save_dlg)
    
    if auto_save_dlg.is_config_changed():
        time_interval, repo_auto_save_config = auto_save_dlg.get_auto_config()
        controller.update_auto_save_config(repo_auto_save_config, time_interval)
    

#=======================================================================================
def cnfg_comparison_tool(controller):
#=======================================================================================
    '''
    description: config compare tool, default is WinMergeU
    parameter  : controller, the DM main class instance, get interface to other components from it
    ''' 
    
    options = {}
    options['defaultextension'] = '*.exe'
    options['filetypes'] = [('excutable file', '*.exe')]
    options['initialdir'] = controller.get_work_dir()
    options['initialfile'] = 'WinMergeU'
    options['parent'] = controller.root
    options['title'] = 'Config Comparison Tool'
    
#    cmd_file_path = asksaveasfilename(**options)
    cmd_file_path = askopenfilename(**options)
    controller.set_compare_tool(cmd_file_path)
    
#=======================================================================================
def about(controller):
#=======================================================================================
    '''
    show version information
    '''
    about_dlg = AboutDialog(controller.root)
    controller.root.wait_window(about_dlg)

#=======================================================================================
def help_doc():
#=======================================================================================
    pass


#=======================================================================================
def display_files(path):
#=======================================================================================
    os.chdir(path)
    filelist = []
    for files in os.listdir("."):
        if os.path.isdir(files) == True:
            continue
#        if files.endswith(".git"):
#            continue
        filelist.append(files)
    return filelist
    
##=======================================================================================
#def select_file():
##=======================================================================================
#    filename = askopenfilename(filetypes=[("allfiles","*"),("pythonfiles","*.py")])
#    return filename


##=======================================================================================
#def select_folder():
##=======================================================================================
#    dirname = askdirectory(initialdir="/",title='Please select a directory')
##    dirname = askdirectory(parent=root,initialdir="/",title='Please select a directory')
#    return dirname

##=======================================================================================
#def config_git():
##=======================================================================================
#    gitdir = askdirectory(initialdir="/",title='Please select git installation path')
##    dirname = askdirectory(parent=root,initialdir="/",title='Please select a directory')
##    print gitdir
    